﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace ShaHashChecker
{
    class HashChecker
    {
        private const string AppTitle = "SHA1 Hash Checker by Assaf Stone.";
        private const string Subtitle =
            "Hashes are checked locally.\nNeither passwords nor hashes are uploaded anywhere, anytime in any way.";

        private const string HelpText = "Usage: ShaHashChecker.exe [/password | /text:phrase] [/pad:number of characters]\n\t[/search:SHA1 hash list File]\n";
        private const string KeyValuePattern = "^\\/(?<key>\\w+):(?<value>\\w+)$";
        private const string TextPattern = "^\\/text:(?<value>\\w+)$";
        private const string PasswordPattern = "^\\/(?<key>password)$";

        static void Main(string[] args)
        {
            Console.WriteLine("\n{0}\n{1}\n", AppTitle, new string('-', AppTitle.Length));

            if (args.Contains("/?"))
            {
                Console.WriteLine(HelpText);
                return;
            }

            try
            {
                var passwordArgument = args.Single(a => Regex.IsMatch(a, TextPattern) || Regex.IsMatch(a, PasswordPattern));
                var source = GetPassword(passwordArgument);

                var hashString = HashHelper.GetHashString(source);

                Console.WriteLine("Hash for text:\t{0}", hashString);

                var pad = HashHelper.GetPad(args);
                if (pad > 0)
                {
                    hashString = new string('0', pad) + hashString.Substring(pad);
                    Console.WriteLine("Padded hash:\t{0}", hashString);
                }

                const string searchPattern = "/search:";
                var filePath = args.SingleOrDefault(a => a.ToLower().StartsWith(searchPattern));

                if (filePath != null)
                {
                    filePath = filePath.Substring(searchPattern.Length);
                    
                    var prevForegroundColor = Console.ForegroundColor;
                    var found = HashHelper.CheckHash(hashString, filePath);

                    Console.ForegroundColor = found ? ConsoleColor.Red : ConsoleColor.Green;
                    Console.WriteLine(found ? "Your password has been compromised!!!\nReplace it in *EVERY* account it was used, and never use it again!" : "Your password is safe. Continue as usual. :)");

                    Console.ForegroundColor = prevForegroundColor;
                }

                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();
            }
            catch (Exception)
            {
                Console.WriteLine("Invalid Input!\n\n{0}\n", HelpText);
            }
        }

        private static string GetPassword(string passwordArgument)
        {
            // Try /Key:Value pattern
            var regex = GetKeyValueRegex();
            var match = regex.Match(passwordArgument);
            if (!match.Success)
            {
                // Try /password pattern
                regex = new Regex(PasswordPattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline);
                match = regex.Match(passwordArgument);

                if (!match.Success)
                {
                    throw new ArgumentException();
                }
            }

            string source;
            switch (match.Groups["key"].Value)
            {
                case "password":
                    source = GetPasswordInput("Enter password:");
                    break;
                case "text":
                    source = match.Groups["value"].Value;
                    break;
                default:
                    throw new ArgumentException();
            }
            return source;
        }

        private static Regex GetKeyValueRegex()
        {
            return new Regex(KeyValuePattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase | RegexOptions.Singleline);
        }

        private static string GetPasswordInput(string prompt)
        {
            Console.Write("{0} ", prompt.Trim());
            var pass = string.Empty;
            ConsoleKeyInfo key;

            do
            {
                key = Console.ReadKey(true);

                // Backspace Should Not Work
                if (key.Key == ConsoleKey.Backspace)
                {
                    if (pass != string.Empty)
                    {
                        Console.Write("\b \b");
                        pass = pass.Remove(pass.Length - 1);
                    }
                }
                else if (key.Key != ConsoleKey.Enter)
                {
                    pass += key.KeyChar;
                    Console.Write("*");
                }
            }
            // Stops Receving Keys Once Enter is Pressed
            while (key.Key != ConsoleKey.Enter);

            Console.WriteLine("\n");
            return pass;
        }
    }
}
